//
//  main.m
//  Block的使用
//
//  Created by apple on 15/8/30.
//  Copyright (c) 2015年 戴维营. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "RedWolf.h"

//block对象作为函数参数

typedef int (^BlockType)(int a,int b);

void math (int a,int b,BlockType op){
    NSLog(@"result : %d",op(a,b));
};

int abc = 1;
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
#if 0

//    Block类型：一个拥有许多变量并且包含了对这些变量的操作表达式（代码块）。不同语言有着不同的实现和叫法，如闭包、Lambda表达式、匿名函数等等。
        
// 返回值类型（函数的名称）（参数的类型）＝ ^返回值类型（参数类型 参数名，参数类型 参数名）；
        int (^add)(int,int) = ^int(int a,int b)
        {
            return a + b;
        };
        
        int result = add(1,3);
        
        NSLog(@"%d",result);
        
#endif
      
//        Blcok对象的创建

//        1、Block函数类似于匿名函数，因此需要马上赋值给一个指针变量或者作为函数的参数进行传递。
        
//        2、当block对象的返回值类型可以由return后的表达式推倒出来时，可以省略不写。
        
//        3、当block对象没有参数的时候，可以省略参数列表不写。
#if 0
        
//        block对象和局部变量；
        
//        1、一个普通的局部变量，不能在block中进行修改；
        
//        －－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－
        
//        2、普通的局部变量，在创建block对象的时候，会在block中复制产生一个只读的变量；
        
//        －－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－
        int other = 123;
      
        
        
//        用两个下划线__block修饰的局部变量，是可以在blcok对象中修改外部的局部变量的；
//        __block int other = 123;
        NSLog(@"外部:%p,%d",&other,other);
        int (^add)(int,int) = ^(int a, int b){
//            other = 234;
            NSLog(@"内部：%p,%d",&other,other);
            NSLog(@"内部：%d",other);
            NSLog(@"内部abc：%d",abc);
            return a + b;
        };
        other = 321;
        NSLog(@"调用之前：%p，%d",&other,other);
        
        int result = add(1,2);
        NSLog(@"%d",result);
        
        
#endif
        
//        Block对象和静态变量
        
//        blcok对象中可以直接修改外部的静态变量；
        
#if 0

//        地址不变，对同一个变量进行修改；
        static int other = 123;
        NSLog(@"外部：%p,%d",&other,other);
        
        int (^add)(int, int) = ^(int a, int b)
        {
            other = 234;
            NSLog(@"内部: %p,%d",&other,other);
            return a + b;
        };
        
        other = 345;
        NSLog(@"调用之前：%p,%d",&other,other);
        
        add(1,2);
        NSLog(@"调用之后: %p,%d",&other,other);
        
#endif
        
//        block对象与全局变量；
        
#if 0
      
//        blcok对象中可以直接的修改全局变量；
        NSLog(@"外部: %p,%d",&abc,abc);
        int (^add)(int, int) = ^(int a,int b)
        {
            NSLog(@"内部:%p,%d",&abc,abc);
            abc = 2;
            return a + b;
        };
        abc = 3;
        NSLog(@"调用之前:%p,%d",&abc,abc);
        add(1,2);
        NSLog(@"调用之后: %p,%d",&abc,abc);

#endif
        
//        block对象作为函数参数
//        block对象作为类的属性
        
#if 0
        
//      block对象作为函数参数，可以直接在调用函数的时候创建对象；
        
        
        RedWolf *redWolf = [RedWolf new];
        redWolf.catchBlock = ^{
            NSLog(@"灰太狼抓啊！！！");
        };
        
        [redWolf eatSheep];
        
        NSArray *array = @[@1,@4,@2,@9,@5];
        NSArray *str = [array sortedArrayUsingComparator:^NSComparisonResult(NSNumber *obj1, NSNumber *obj2) {
            return [obj1 compare:obj2];
        }];
        NSLog(@"%@",array);
        NSLog(@"----------");
        NSLog(@"%@",str);
        
        math(11, 2, ^int(int a, int b) {
            return a + b;
        });
#endif
        
        
//        在手动引用计数的情况下；
//        block的三种不同类型；
#if 1
        
        
//        就普通情况下得到的block对象，一般在文本段；
        void (^pro)() = ^{
            NSLog(@"普通情况下");
        };
        NSLog(@"%@",[pro class]);
        
        
//        如果block对象使用了局部变量，则分配在栈上；(在自动引用计数的情况下，系统会自动的把对象移到堆上面)
        int a = 123;
        void (^p)() = ^
        {
            NSLog(@"%d",a);
//            NSLog(@"这是在有局部变量的时候");
        };
        NSLog(@"1\%@",[p class]);
//        NSLog(@"%d",a);//为什么这里加了这么一句类型就变了；
        
        
//        对栈上面的blcok对象进行复制，它所产生的新对象在堆上分配；
        void (^pi)() = [p copy];
        NSLog(@"%@",[pi class]);

        
#endif
        
    }
    return 0;
}
